#include "BDSworkmain.h"
#include "ui_BDSworkmain.h"

//引入串口变量
extern QSerialPort *serial;
extern QSerialPort *serial_send;

extern QString filepath;
extern network_confdef netconf;

QByteArray cur_lon={0};
QByteArray cur_lat={0};

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{   
    ui->setupUi(this);

    setAttribute(Qt::WA_StyledBackground);

    ui->web_widget->setUrl(QUrl("http://localhost:8000/map.html"));

    this->setWindowTitle("北斗上位机软件");

    socket = new QTcpSocket;

    udpSocket = new QUdpSocket(this);

    //打开配置文件并指定为ini格式
    QSettings* configini = new QSettings("E:/QT/Project/BDSwork/config.ini", QSettings::IniFormat);

    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>串口初始化配置<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    //将串口与串口处理函数连接起来
    connect(serial,&QSerialPort::readyRead,this,&Widget::rcvserialSLOTS);

    //建立串口波特率映射表
    baudrateMap["1200"] = QSerialPort::Baud1200;
    baudrateMap["2400"] = QSerialPort::Baud2400;
    baudrateMap["4800"] = QSerialPort::Baud4800;
    baudrateMap["9600"] = QSerialPort::Baud9600;
    baudrateMap["19200"] = QSerialPort::Baud19200;
    baudrateMap["38400"] = QSerialPort::Baud38400;
    baudrateMap["57600"] = QSerialPort::Baud57600;
    baudrateMap["115200"] = QSerialPort::Baud115200;

    //建立串口数据位映射表
    databitMap["8"] = QSerialPort::Data8;
    databitMap["7"] = QSerialPort::Data7;
    databitMap["6"] = QSerialPort::Data6;
    databitMap["5"] = QSerialPort::Data5;

    //建立串口停止位映射表
    stopbitMap["1"] = QSerialPort::OneStop;
    stopbitMap["1.5"] = QSerialPort::OneAndHalfStop;
    stopbitMap["2"] = QSerialPort::TwoStop;

    //建立串口奇偶校验位映射表
    parityMap["None"]= QSerialPort::NoParity;
    parityMap["Odd"]= QSerialPort::OddParity;
    parityMap["Even"]= QSerialPort::EvenParity;

    //根据配置文件进行初始化
    QString default_serial = configini->value("Receive/Serial/Port").toString();
    serial->setPort(QSerialPortInfo(default_serial));

    QString default_baudrate = configini->value("Receive/Serial/Baudrate").toString();
    serial->setBaudRate(baudrateMap[default_baudrate]);

    QString default_databitText = configini->value("Receive/Serial/DataBit").toString();
    serial->setDataBits(databitMap[default_databitText]);

    QString default_stopbitText = configini->value("Receive/Serial/StopBit").toString();
    serial->setStopBits(stopbitMap[default_stopbitText]);

    QString default_parityText = configini->value("Receive/Serial/Parity").toString();
    serial->setParity(parityMap[default_parityText]);


    //发信串口配置
    default_serial = configini->value("Send/Serial/Port").toString();
    serial_send->setPort(QSerialPortInfo(default_serial));

    default_baudrate = configini->value("Send/Serial/Baudrate").toString();
    serial_send->setBaudRate(baudrateMap[default_baudrate]);

    default_databitText = configini->value("Send/Serial/DataBit").toString();
    serial_send->setDataBits(databitMap[default_databitText]);

    default_stopbitText = configini->value("Send/Serial/StopBit").toString();
    serial_send->setStopBits(stopbitMap[default_stopbitText]);

    default_parityText = configini->value("Send/Serial/Parity").toString();
    serial_send->setParity(parityMap[default_parityText]);

    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>TCP初始化配置<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    //定义变量


    //将可接收数据的信号和信号处理函数连接起来
    connect(socket,&QTcpSocket::readyRead,this,&Widget::rcvtcpSLOTS);

    //读取配置文件中的网口相关配置
    QString default_serverip = configini->value("Receive/Network/TCP_IP").toString();
    netconf.rcv_tcp_ip = default_serverip;

    QString default_serverport = configini->value("Receive/Network/TCP_Port").toString();
    netconf.rcv_tcp_port = default_serverport;

    //读取配置文件中的网口相关配置
    default_serverip = configini->value("Send/Network/TCP_IP").toString();
    netconf.send_tcp_ip = default_serverip;

    default_serverport = configini->value("Send/Network/TCP_Port").toString();
    netconf.send_tcp_port = default_serverport;


    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>UDP初始化配置<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


    QString default_clientip = configini->value("Send/Network/UDP_IP").toString();
    netconf.send_udp_ip = default_clientip;

    QString default_clientport = configini->value("Send/Network/UDP_Port").toString();
    netconf.send_udp_port = default_clientport;


    //删除配置文件指针
    delete configini;
}

Widget::~Widget()
{
    delete ui;

    //文件结束后释放变量指针
    free(serial);
    free(serial_send);
    free(socket);
}

//按下配置后弹出设置窗口
void Widget::on_configbutton_clicked()
{
    Config *configWindow = new Config;
    configWindow->show();
}

//开始&暂停按钮
void Widget::on_startbutton_clicked()
{
    //设立手动关闭网口的标志位
    humanclose_flag=0;


    //判断按钮状态，实现同一按钮不同操作（开始接受和暂停接收）
    if(ui->startbutton->text()=="开始接收")
    {
        //点击开始后读取配置文件
        //读取配置文件
        QSettings* configini = new QSettings("E:/QT/Project/BDSwork/config.ini", QSettings::IniFormat);
        //根据配置文件进行初始化
        QString default_serial = configini->value("Receive/Serial/Port").toString();
        serial->setPort(QSerialPortInfo(default_serial));

        QString default_baudrate = configini->value("Receive/Serial/Baudrate").toString();
        serial->setBaudRate(baudrateMap[default_baudrate]);

        QString default_databitText = configini->value("Receive/Serial/DataBit").toString();
        serial->setDataBits(databitMap[default_databitText]);

        QString default_stopbitText = configini->value("Receive/Serial/StopBit").toString();
        serial->setStopBits(stopbitMap[default_stopbitText]);

        QString default_parityText = configini->value("Receive/Serial/Parity").toString();
        serial->setParity(parityMap[default_parityText]);


        //发信串口配置
        QString default_serial_send = configini->value("Send/Serial/Port").toString();
        serial_send->setPort(QSerialPortInfo(default_serial_send));

        QString default_baudrate_send = configini->value("Send/Serial/Baudrate").toString();
        serial_send->setBaudRate(baudrateMap[default_baudrate_send]);

        default_databitText = configini->value("Send/Serial/DataBit").toString();
        serial_send->setDataBits(databitMap[default_databitText]);

        default_stopbitText = configini->value("Send/Serial/StopBit").toString();
        serial_send->setStopBits(stopbitMap[default_stopbitText]);

        default_parityText = configini->value("Send/Serial/Parity").toString();
        serial_send->setParity(parityMap[default_parityText]);



        //读取配置文件中的网口相关配置
        QString default_serverip = configini->value("Receive/Network/TCP_IP").toString();
        netconf.rcv_tcp_ip = default_serverip;

        QString default_serverport = configini->value("Receive/Network/TCP_Port").toString();
        netconf.rcv_tcp_port = default_serverport;

        //读取配置文件中的网口相关配置
        default_serverip = configini->value("Send/Network/TCP_IP").toString();
        netconf.send_tcp_ip = default_serverip;

        default_serverport = configini->value("Send/Network/TCP_Port").toString();
        netconf.send_tcp_port = default_serverport;


        //读取UDP配置
        QString default_clientip = configini->value("Send/Network/UDP_IP").toString();
        netconf.send_udp_ip = default_clientip;

        QString default_clientport = configini->value("Send/Network/UDP_Port").toString();
        netconf.send_udp_port = default_clientport;

        delete configini;


        //当选择串口时，打开串口
        if(ui->comboBox_rcv->currentText()=="串口")
        {
            bool info = serial->open(QIODevice::ReadWrite);
            if(info == true)
            {
                QMessageBox::information(this,"连接提示","串口打开成功！");
                qDebug()<<"串口打开成功!";

                //执行切换主界面状态的函数
                Widget::to_sta_rcv();
            }
            else
            {
                QMessageBox::warning(this,"连接提示","串口打开失败!请检查你的串口配置!");
                qDebug()<<"串口打开失败!请检查你的串口配置!";
            }
            if(ui->comboBox_send->currentText()=="UDP")
            {
                udpSocket->bind(netconf.send_udp_port.toInt());
            }
        }


        //当选择网口或是需要通过网口发送数据时，打开网口
        else if(ui->comboBox_rcv->currentText()=="网口")
        {
            //断开之前所有的槽
            disconnect(socket, &QTcpSocket::connected, nullptr, nullptr);
            disconnect(socket, &QTcpSocket::disconnected, nullptr, nullptr);
            disconnect(socket, &QTcpSocket::errorOccurred, nullptr, nullptr);

            //尝试连接服务端
            socket->connectToHost(QHostAddress(netconf.rcv_tcp_ip),netconf.rcv_tcp_port.toShort());

            //连接成功后进行按钮的转换，并且禁止其他操作
            connect(socket,&QTcpSocket::connected,[this]()
                    {
                        QMessageBox::information(this,"连接提示","连接服务器成功！");

                        //执行切换主界面状态的函数
                        Widget::to_sta_rcv();
                    });

            //当使用者没有操作停止而出现连接断开的情况时，断开连接，并且恢复开始接收的按钮
            connect(socket,&QTcpSocket::disconnected,[this]()
                    {
                        if(humanclose_flag==0)
                        {
                            QMessageBox::warning(this,"连接提示","连接异常，网络断开！");
                            Widget::to_sta_stop();
                        }
                    });

            //如果在连接时出现连接失败，则出现警告提示
            connect(socket,&QTcpSocket::errorOccurred,[this]()
                    {
                        QMessageBox::warning(this,"接收测试","连接异常，请检查你的网口设置！");
                        Widget::to_sta_stop();
                    });
        }


        //当需要通过网口发送数据，尝试连接目标网口
        if(ui->comboBox_send->currentText()=="TCP"&&ui->sendbutton->isChecked())
        {
            //断开之前所有的槽
            disconnect(socket, &QTcpSocket::connected, nullptr, nullptr);
            disconnect(socket, &QTcpSocket::disconnected, nullptr, nullptr);
            disconnect(socket, &QTcpSocket::errorOccurred, nullptr, nullptr);
            //尝试连接服务端
            socket->connectToHost(QHostAddress(netconf.send_tcp_ip),netconf.send_tcp_port.toShort());

            //连接成功后进行按钮的转换，并且禁止其他操作
            connect(socket,&QTcpSocket::connected,[this]()
                    {
                        QMessageBox::information(this,"连接提示","连接服务器成功！");
                    });

            //当使用者没有操作停止而出现连接断开的情况时，断开连接，并且恢复开始接收的按钮
            connect(socket,&QTcpSocket::disconnected,[this]()
                    {
                        if(humanclose_flag==0)
                        {
                            socket->disconnectFromHost();
                            Widget::to_sta_stop();
                            QMessageBox::warning(this,"连接提示","连接异常，网络断开！");
                        }
                    });

            //如果在连接时出现连接失败，则出现警告提示
            connect(socket,&QTcpSocket::errorOccurred,[this]()
                    {
                        socket->disconnectFromHost();
                        Widget::to_sta_stop();
                        QMessageBox::warning(this,"连接提示","连接异常，请检查你的网口设置！");
                    });
        }


        //更改主界面的软件题目
        if(ui->comboBox_rcv->currentText()=="串口")
        {
            if(ui->sendbutton->isChecked())
            {
                if(ui->comboBox_send->currentText()=="TCP")
                {
                    this->setWindowTitle(QString("北斗上位机软件 | 串口:")+default_serial_send+QString(" Baud ")
                                         +default_baudrate_send+QString(" | TCP:")
                                         +default_serverip+":"+default_serverport);
                }
                else if(ui->comboBox_send->currentText()=="UDP")
                {
                    this->setWindowTitle(QString("北斗上位机软件 | 串口:")+default_serial_send+QString(" Baud ")
                                         +default_baudrate_send+QString(" | UDP:")
                                         +default_clientip+":"+default_clientport);
                }
            }
        }
        else if(ui->comboBox_rcv->currentText()=="网口")
            {
                if(ui->sendbutton->isChecked())
                {
                    if(ui->comboBox_send->currentText()=="串口")
                    {
                        this->setWindowTitle(QString("北斗上位机软件 | 网口:")+default_serverip+":"+default_serverport +QString(" | 串口:")
                                                                            +default_serial_send+QString(" Baud ")
                                                                            +default_baudrate_send);
                    }
                }
            }


        //检测存储按钮是否打开，若打开则清空目标路径的数据
        if(ui->savebutton->isChecked())
        {
            QFile file(filepath);

            // 打开文件
            if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
                qDebug() << "打开文件失败";
            } else {
                qDebug() << "文件打开成功";
            }

            // 创建QTextStream对象，并与QFile对象关联
            QTextStream out(&file);

            // 向文件写入空白文本以清空文本
            out << "";
            file.close();
        }
    }
    else if(ui->startbutton->text()=="停止接收")
    {
        humanclose_flag = 1;
        socket->disconnectFromHost();
        udpSocket->disconnect();
        serial->close();
        qDebug()<<"接收模块已关闭!";
        Widget::to_sta_stop();
    }
}

//接收串口数据
void Widget::rcvserialSLOTS()
{

    //读取串口原始数据
    QByteArray serialrawdata = serial->readAll();

    //定义有效数据帧帧头
    QByteArray serialrawdatabegin = "$AE,";

    //截取有效数据帧
    int index=0;
    QByteArray serialrawdatacashe;
    index = serialrawdata.indexOf(serialrawdatabegin,index); //查找帧头
    if(index<serialrawdata.size())
    {
        int serialrawdatalens = serialrawdata.size() - index + 1; //计算帧长度
        serialrawdatacashe = serialrawdata.mid(index,serialrawdatalens); //截取出数据帧
    }

    //将有效数据帧中的经纬度数据取出
    QByteArray lon = serialrawdatacashe.split(',').at(1);
    QByteArray lat = serialrawdatacashe.split(',').at(2);

    //为方便发送，为全局变量赋值
    QByteArray cur_lon=lon;
    QByteArray cur_lat=lat;

    //获取系统当前时间并格式化
    QDateTime dateTime= QDateTime::currentDateTime();
    QString timestr = dateTime.toString("yyyy-MM-dd,hh:mm:ss");

    addMapMarker(cur_lon.toDouble(), cur_lat.toDouble());

    //将数据显示在屏幕上
    ui->positionlist->append(">>>>>>>>>>>>>>>>>>>");
    ui->positionlist->append("时间：" + timestr);
    ui->positionlist->append("经度：" + lon);
    ui->positionlist->append("纬度：" + lat);
    ui->positionlist->append(">>>>>>>>>>>>>>>>>>>");


    //当存储数据打开时，往存储数据文件中写入数据
    if(ui->savebutton->isChecked())
    {
        QFile file(filepath);

        // 打开文件
        file.open(QIODevice::ReadWrite | QIODevice::Text| QIODevice::Append);

        // 创建QTextStream对象，并与QFile对象关联
        QTextStream out(&file);

        // 向文件写入文本
        out << "#Serial_Position,"<<timestr<<","<<lon<<","<<lat<<"\n";
        file.close();
    }

    //当发送数据打开时，往设定目标发送数据
    if(ui->sendbutton->isChecked())
    {
        if(ui->comboBox_send->currentText()=="TCP")
        {
            if(cur_lon.size()!=0&&cur_lat.size()!=0)
            {
                QByteArray tcpdata=encodeLocationData(cur_lon.toDouble(),cur_lat.toDouble());
                socket->write(tcpdata);
                cur_lon.clear();
                cur_lat.clear();
            }
        }

        else if(ui->comboBox_send->currentText()=="UDP")
        {
            if(cur_lon.size()!=0&&cur_lat.size()!=0)
            {
                QByteArray tcpdata=encodeLocationData(cur_lon.toDouble(),cur_lat.toDouble());

                udpSocket->writeDatagram(tcpdata,QHostAddress(netconf.send_udp_ip),netconf.send_udp_port.toInt());

                cur_lon.clear();
                cur_lat.clear();
            }
        }
    }

}


void Widget::rcvtcpSLOTS()
{
    //读取网口接收的所有消息
    QByteArray tcprawdata = socket->readAll();

    //对网口读取的数据进行解码
    QPointF tcpdata = decodeLocationData(tcprawdata);

    //将经纬度信息从解码出的有效数据帧中取出
    double lon = tcpdata.x();
    double lat = tcpdata.y();

    //为方便发送数据，为全局变量赋值
    QByteArray cur_lon = QByteArray::number(lon,'f',5);
    QByteArray cur_lat = QByteArray::number(lat,'f',5);

    //读取系统时间并格式化
    QDateTime dateTime= QDateTime::currentDateTime();
    QString timestr = dateTime.toString("yyyy-MM-dd,hh:mm:ss");

    addMapMarker(cur_lon.toDouble(), cur_lat.toDouble());

    //将数据显示在屏幕上
    ui->positionlist->append(">>>>>>>>>>>>>>>>>>>");
    ui->positionlist->append("时间：" + timestr);
    ui->positionlist->append("经度：" + QString::number(lon,'f',5));
    ui->positionlist->append("纬度：" + QString::number(lat,'f',5));
    ui->positionlist->append(">>>>>>>>>>>>>>>>>>>");


    //当存储数据打开时，往存储数据文件中写入数据
    if(ui->savebutton->isChecked())
    {

        QFile file("E:/QT/Project/BDSwork/savedata.txt");
        // 打开文件
        file.open(QIODevice::ReadWrite | QIODevice::Text| QIODevice::Append);
        // 创建QTextStream对象，并与QFile对象关联
        QTextStream out(&file);
        // 向文件写入文本
        out << "#TCP_Position,"<<timestr<<","<<lon<<","<<lat<<"\n";
        file.close();
    }


    //当发送数据打开时，往设定目标发送数据
    if(ui->sendbutton->isChecked())
    {
        if(ui->comboBox_send->currentText()=="串口")
        {
            bool info = serial_send->open(QIODevice::WriteOnly);
            if(info == true)
            {
                QMessageBox::information(this,"连接提示","串口打开成功！");
            }

            //按照数据帧格式发送数据
            if(cur_lon.size()!=0&&cur_lat.size()!=0)
            {
                QByteArray mes_data = "$AE,"+cur_lon+","+cur_lat+"\r\n";
                serial_send->write(mes_data);
                mes_data.clear();
                // serial_send->write("");
                // serial_send->write(cur_lon);
                // serial_send->write(",");
                // serial_send->write(cur_lat);
                // serial_send->write("\r\n");
                cur_lon.clear();
                cur_lat.clear();
            }
        }
    }

}

// 将字节数组转换为经纬度坐标
QPointF Widget::decodeLocationData(const QByteArray &data)
{
    // 验证数据完整性（固定长度：2+8+8+1=19字节）
    if (data.size() != 19) {
        return QPointF(qQNaN(), qQNaN()); // 返回无效坐标
    }

    QDataStream stream(data);
    stream.setByteOrder(QDataStream::BigEndian); // 根据实际情况设置字节序

    // 读取并验证识别字
    quint16 identifier;
    stream >> identifier;
    const quint16 EXPECTED_ID = 0xAABB;
    if (identifier != EXPECTED_ID) {
        return QPointF(qQNaN(), qQNaN());
    }

    // 读取经度和纬度
    double longitude, latitude;
    stream >> longitude >> latitude;

    // 忽略保留位
    char reserved;
    stream >> reserved;

    return QPointF(longitude, latitude); // (经度, 纬度)
}

// 将经纬度坐标转换为字节数组
QByteArray Widget::encodeLocationData(double longitude, double latitude)
{
    QByteArray data;
    QDataStream stream(&data, QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::BigEndian); // 与解码保持一致

    // 写入固定识别字
    stream << static_cast<quint16>(0xAABB);

    // 写入坐标数据
    stream << longitude << latitude;

    // 写入保留位（空值填充为0）
    stream << static_cast<char>(0);

    return data; // 总长度19字节
}

//切换成
void Widget::to_sta_stop()
{
    ui->startbutton->setText("开始接收");
    ui->configbutton->setEnabled(1);
    ui->savebutton->setEnabled(1);
    ui->sendbutton->setEnabled(1);
    socket->disconnectFromHost();
    udpSocket->disconnect();
    serial->close();
    serial_send->close();
}

void Widget::to_sta_rcv()
{
    ui->startbutton->setText("停止接收");
    ui->configbutton->setEnabled(0);
    ui->savebutton->setEnabled(0);
    ui->sendbutton->setEnabled(0);
}


void Widget::addMapMarker(double lon, double lat)
{
    // 构建JS调用字符串
    QString js = QString("addMarker(%1, %2);").arg(lon,0,'f',5).arg(lat,0,'f',5);
    // 异步执行JS（确保页面加载完成）
    ui->web_widget->page()->runJavaScript(js);
}

